package com.utilities.IO.fileWriters;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Set;
import java.util.TreeSet;

import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.Element;

import com.utilities.IO.FileUtilities;
import com.utilities.dataStructures.Range;
import com.utilities.fastaUtilities.FindGenes;
import com.utilities.fastaUtilities.OtherUtilities;
import com.utilities.parsers.coordsParser.ParseCoordsFileParser;
import com.utilities.visualiser.PrepareXMLFile;

public class DeNovo2 
{
	private PrepareXMLFile prepareXMLFile = null;
	private static String[] colors = {"maroon","red","blue","green","orange", "purple","fuchsia","navy",
		"lime","olive","yellow","teal","aqua","silver","gray","white","black"};
	private static String workSpace = "C:/Users/bansalp/Desktop/DeNovo/DeNovo/7328/DeNovo/";
	private static String pathwayMappingData = "C:/Users/bansalp/KeggData/mappedData.dat"; 

	public static void main(String args[]) throws Exception
	{
		//		findGenes();
		separateContigsInDifferentFiles(workSpace + "scaffoldFile_bak.txt", workSpace + "contigs");
		// input Files
		String tilingFile = workSpace + "tiling.txt";
		String initialContigsFile = workSpace + "scaffoldFile_bak.txt";
		String coordsFile = workSpace + "nucmer.coords";
		String allGenesPossibleFile = "C:/Users/bansalp/Desktop/AllGenesPossible.out";
		String resultGff3File = workSpace + "resultGff3";

		// Generated files
		//		String rearrangedContigsFile = "";
		String gapsFile = workSpace + "gaps.txt";
		String tiledContigsFile = workSpace + "tiledContigs.txt";
		String missingGenesFile = workSpace + "genesShouldBeInGapsButNotFound.txt";
		String gapsWithNoGenesFile = workSpace + "noGenesGaps.txt";
		String allGenesFoundOnContigs = workSpace + "allGenesFoundOnContigs.txt";
		String genesInGapsFoundSomeWhereElse = workSpace + "genesShouldInGapsButFoundSomeWhereElse.txt";
		String excludedContigsFile = workSpace + "excludedData.txt";
		String notAlignedContigsFile = workSpace + "notAlignedContigs.txt";
		String mergedcontigs = workSpace + "mergedContigs.txt";
		String geneAbsent = workSpace + "genesAbsent.txt";
		String scaffoldFile = workSpace + "scaffold.txt";
		String pathwayForMissingGenesFile = workSpace + "pathway_missingGenes.txt";
		String pathwaysForAbsentGenesFile = workSpace + "pathway_absentGenes.txt";

		int seQLength = 4639675;
		DeNovo2 deNovo2 = new DeNovo2();
		ArrayList<ArrayList<Range>> lists = deNovo2.filterTilingFile(seQLength, 
				tilingFile, 
				gapsFile, 
				tiledContigsFile);

		// Total contigs that were tiled including overlaps
		ArrayList<Range> contigs = lists.get(0);
		// Total gaps found
		ArrayList<Range> gaps = lists.get(1);
		// All genes found in the reference
		ArrayList<Range> allGenes = FileUtilities.readFromFile(allGenesPossibleFile);

		// A map from gaps to genes that are possible in those gaps
		HashMap<Range, ArrayList<Range>> hashMap = deNovo2.findGenesInGaps(gaps, allGenes,gapsWithNoGenesFile);

		lists = deNovo2.FilterGenesFoundAndNotFoundInGaps(hashMap,missingGenesFile,
				genesInGapsFoundSomeWhereElse , resultGff3File);

		// typically the sum of all these three should be equal to the allGenes 
		ArrayList<Range> allGenesFoundInContigs = lists.get(2);
		ArrayList<Range> missingGenesEvenInGaps = lists.get(1);
		// Genes found in gap but found somewhere else
		ArrayList<Range> foundGenesInGaps = lists.get(0);

		args = new String[3];
		args[0] = tilingFile;
		args[1] = initialContigsFile;
		args[2] = workSpace + "contigsNotFound2.txt";
		OtherUtilities otherUtilities = new OtherUtilities();

		// list all the contigs that were not included in the tiling
		lists = deNovo2.findExcludedContigRanges(
				otherUtilities.reArrangeContigs2(args),coordsFile);
		ArrayList<Range> mergedContigs = deNovo2.mergeOverLappingContigs(contigs,seQLength);
		ArrayList<Range> excludedOnes = lists.get(0);
		ArrayList<Range> notAligned = lists.get(1);
		FileUtilities.WriteToFile(excludedOnes, excludedContigsFile);
		FileUtilities.WriteToFile(notAligned, notAlignedContigsFile);
		int totalContigs = otherUtilities.countScaffolds(initialContigsFile);
		ParseCoordsFileParser allContigsFileParser = new ParseCoordsFileParser();
		TreeSet<String> exContigs = new TreeSet<String>();
		for (Range excludedContig : excludedOnes)
		{
			String name = allContigsFileParser.parseCoordsFileLine(excludedContig.getMetadata())[14];
			exContigs.add(name);
		}
		FileUtilities.WriteToFile(mergedContigs, mergedcontigs);
		int totalContigsLength = 0;
		double actualContigLength = 0.0;
		for (Range contig : contigs)
		{
			totalContigsLength = totalContigsLength + contig.getOtherData();
		}
		for (Range contig : mergedContigs)
		{
			actualContigLength = actualContigLength + contig.getActualLength();
		}
		System.out.println("Total contigs accounted / Total contigs \t" + contigs.size() + " / " + totalContigs);
		System.out.println("Total contigs left / Total contigs \t" + exContigs.size() + " / " + totalContigs);
		System.out.println("Total contigs not Aligned / Total contigs \t" + notAligned.size() + " / " + totalContigs);
		System.out.println("Total contigs after merging \t" + mergedContigs.size() + " / " + totalContigs);
		System.out.println("Total number of gaps \t" + gaps.size());
		int temp = deNovo2.findTotalLengthOfRanges(mergedContigs);
		System.out.println("Total Contig length (on reference after merging) \t" + deNovo2.findTotalLengthOfRanges(mergedContigs));
		int gapLength = deNovo2.findTotalLengthOfRanges(gaps);
		System.out.println("Total Gap Length is \t" + gapLength);
		System.out.println("Total Contig length (after mapping and without removing hangovers) \t" + totalContigsLength);
		System.out.println("Total Contig length (after mapping and after removing hangovers) \t" + actualContigLength);
		int temp3 =  gapLength + totalContigsLength;
		System.out.println("Total scaffold length (with hangovers) \t" + temp3 );
		double temp2 = gapLength + actualContigLength;
		System.out.println("Total scaffold length (without hangovers) \t" + temp2 );
		System.out.println("Genes found on contigs/Total Genes \t" + allGenesFoundInContigs.size()  + " / "+ allGenes.size());
		System.out.println("Genes found in gaps/Total Genes \t" + missingGenesEvenInGaps.size() + " / "+ allGenes.size());
		System.out.println("Genes in gaps but found on contigs \t" + foundGenesInGaps.size());
		double ratio = ((double) totalContigsLength)/((double)temp);
		System.out.println("agg ratio (sum contig length with hangovers)/(sum of mapped regions) " + ratio);
		ratio = ((double) actualContigLength)/((double)temp);
		System.out.println("agg ratio (sum contig length without hangovers)/(sum of mapped regions) " + ratio);
		//		deNovo2.print(mergedContigs,gaps,workSpace + mergedcontigs);
		FileUtilities.WriteToFile(allGenesFoundInContigs, allGenesFoundOnContigs);
		ArrayList<String> genesAbsent = new ArrayList<String>();
		for (Range gene : allGenes)
		{
			genesAbsent.add(gene.getMetadata());
		}
		for (Range gene : allGenesFoundInContigs)
		{
			genesAbsent.remove(gene.getMetadata().trim());
		}
		for (Range gene : missingGenesEvenInGaps)
		{
			genesAbsent.remove(gene.getMetadata().trim());
		}
		FileUtilities.writeToFile(genesAbsent, geneAbsent);
		deNovo2.print(mergedContigs,gaps,scaffoldFile);
		System.out.println("Genes completely Absent \t" + genesAbsent.size());
		deNovo2.findGCcontent(initialContigsFile, contigs);
		deNovo2.getContigsWithOverHangs(contigs, coordsFile);
		Range medianContig = deNovo2.getMedianContig(contigs);
		System.out.println(medianContig.getMetadata() + " " + medianContig.getActualLength() + " " + 
				medianContig.getLowerLimit() + " " + medianContig.getUpperLimit()
				+ " " + medianContig.getActualLength()/medianContig.length());
		deNovo2.printPathways(missingGenesFile, pathwayForMissingGenesFile);
		deNovo2.printPathways(geneAbsent, pathwaysForAbsentGenesFile);
		deNovo2.makeVisualisation(gaps,seQLength,excludedOnes,mergedContigs);
	}

	private void printPathways(String genesFile, String pathwayOutFile) throws Exception
	{
		HashMap<String,ArrayList<String>> geneToPathway = new HashMap<String, ArrayList<String>>();
		HashMap<String, String> geneIdToDescription = new HashMap<String, String>();
		BufferedReader bufferedReader = new BufferedReader(new FileReader(pathwayMappingData));
		String readLine = bufferedReader.readLine();
		String currentGene = null;
		ArrayList<String> pathways = new ArrayList<String>();
		while(readLine != null)
		{
			if (readLine.startsWith("eco:"))
			{
				String params[] = readLine.split("\t");
				currentGene = params[0].trim();
				String description = params[1].trim();
				geneIdToDescription.put(currentGene,description);
			}
			else if (readLine.trim().length() == 0)
			{
				geneToPathway.put(currentGene, pathways);
				currentGene = null;
				pathways = new ArrayList<String>();
			}
			else
			{
				pathways.add(readLine.trim());
			}
			readLine = bufferedReader.readLine();
		}
		bufferedReader.close();
		PrintWriter printWriter = new PrintWriter(new FileWriter(pathwayOutFile));
		ArrayList<String> missingGenes = FileUtilities.readListFromFile(genesFile);
		Set<String> keyset = geneIdToDescription.keySet();
		for (String missingGene : missingGenes)
		{
			printWriter.println(missingGene);
			for(String key : keyset)
			{
				String description = geneIdToDescription.get(key);
				if (description.contains(missingGene))
				{
					ArrayList<String> arrayList = geneToPathway.get(key);
					printWriter.println("\t\t" + description);
					for(String pathway : arrayList)
					{
						printWriter.println("\t\t" + pathway);
					}
				}
			}
			printWriter.println("\n");
		}
		printWriter.flush();
		printWriter.close();
	}

	private Range getMedianContig(ArrayList<Range> contigs) 
	{
		Collections.sort(contigs, new Comparator<Range>() {

			@Override
			public int compare(Range o1, Range o2) 
			{
				double temp = o1.getActualLength()/o1.length();
				double temp2 = o2.getActualLength()/o2.length();
				double diff = temp - temp2;
				if (diff > 0 ) return 1;
				else if (diff < 0) return -1;
				else return 0;
			}
		});
		return contigs.get(contigs.size() - (int)(Math.floor(((double)contigs.size()/2)) + 1));
	}

	public void findGCcontent(String contigsFile, ArrayList<Range> contigs) throws IOException
	{
		PrintWriter printWriter = new PrintWriter(new FileWriter(workSpace + "GCContent.txt"));
		BufferedReader bufferedReader = new BufferedReader(new FileReader(contigsFile));
		String readLine = bufferedReader.readLine();
		String header = null;
		int total = 0;
		int count = 0;
		int seqLength = 0;
		int contigCounter = 0;
		int totalSequenceRead = 0;
		int previousSeqLength = 0;
		while(readLine != null)
		{
			if (readLine.startsWith(">"))
			{
				if (count > 0)
				{
					printWriter.println(header + " " + count + " " + seqLength + " " + previousSeqLength + " " + ((double)count)/((double)seqLength));
					//					printWriter.println(header + " " + seqLength + " " + previousSeqLength );
					total = total + count;
					header = null;
					count = 0 ;
					totalSequenceRead = totalSequenceRead + seqLength;
					seqLength = 0;
					previousSeqLength = 0;
				}
				String[] params = readLine.split(" ");
				String name = params[0].substring(1).trim();
				for (Range contig : contigs)
				{
					if (contig.getMetadata().equalsIgnoreCase(name))
					{
						header = name;
						previousSeqLength = contig.getOtherData();
						contigCounter++;
						break;
					}
				}
			}
			else
			{
				if (header != null)
				{
					count = count + OtherUtilities.findGCContent(readLine.trim());
					seqLength = seqLength + readLine.trim().length();
				}
			}
			readLine = bufferedReader.readLine();
		}
		if (count > 0)
		{
			printWriter.println(header + " " + count + " " + seqLength + " " + previousSeqLength + " " + ((double)count)/((double)seqLength));
			//			printWriter.println(header + " " + seqLength + " " + previousSeqLength );
			total = total + count;
			header = null;
			count = 0 ;
			totalSequenceRead = totalSequenceRead + seqLength;
			seqLength = 0;
			previousSeqLength = 0;
		}
		System.out.println("Total " + total + " " + totalSequenceRead + " " + ((double)total)/((double)totalSequenceRead) + " " + contigCounter);
		printWriter.println("Total " + total + " " + totalSequenceRead + " " + ((double)total)/((double)totalSequenceRead));
		printWriter.flush();
		printWriter.close();
		bufferedReader.close();
	}

	public static void separateContigsInDifferentFiles(String contigsFile, String outDir) throws Exception
	{
		BufferedReader bufferedReader = new BufferedReader(new FileReader(contigsFile));
		String readLine = bufferedReader.readLine();
		PrintWriter pw = null;
		while(readLine != null)
		{
			if (readLine.startsWith(">"))
			{
				String params[] = readLine.split(" ");
				String name = params[0].trim().substring(1);
				if (pw != null)
				{
					pw.flush();
					pw.close();
					pw = null;
				}
				pw = new PrintWriter(new FileWriter(outDir + File.separator +name+".txt"));
			}
			pw.println(readLine);
			readLine = bufferedReader.readLine();
		}
	}


	public static void findGenes() throws IOException
	{
		String gbkFile = workSpace + "new/Streptococcus_pneumoniae.gb.txt";
		String geneFile = workSpace + "new/genes.fa";
		new FindGenes().setInputFile(gbkFile).setOutpuFile(geneFile).findGenes(); 
		//		RandomAccessFile rand = new RandomAccessFile("C:/Users/bansalp/Desktop/gbkFile2.gbk", "r");
		//		String readLine = rand.readLine();
		//		FindGenes findGenes = new FindGenes();
		//		while(readLine != null)
		//		{
		//			readLine = readLine.trim();
		//			// read only the line that starts with this suffix
		//			if (readLine.startsWith("gene  "))
		//			{
		//				findGenes.makeGeneMap(readLine,rand);
		//			}
		//			else if (readLine.startsWith("ORIGIN"))
		//			{
		//				System.out.println("Gene location read. ");
		//				break;
		//			}
		//			readLine = rand.readLine();
		//		}
		//		rand.close();
		//		HashMap<String,ArrayList<String>> hashMap = findGenes.getMap();
		//		Set<String> keys = hashMap.keySet();
		//		
		//		ArrayList<Range> list3 = new ArrayList<Range>();
		//		for (String key : keys)
		//		{
		//			ArrayList<String> positionsInfo = hashMap.get(key);
		//			for (String positionInfo : positionsInfo)
		//			{
		//				String[] params = positionInfo.split("\\.\\.");
		//				int start = Integer.parseInt(params[0]);
		//				int end = Integer.parseInt(params[1]);
		//				if (start > end)
		//				{
		//					int temp = start; start = end; end = temp;
		//				}
		//				Range range = new Range(start, end, key);
		//				list3.add(range);
		//			}
		//		}
		//		Collections.sort(list3, new RangeComparator());
		//		FileUtilities.WriteToFile(list3,"C:/Users/bansalp/Desktop/AllGenesPossible.out");
	}

	public void getContigsWithOverHangs(ArrayList<Range> contigs, String coordsFile) throws IOException
	{
		ArrayList<Range> overHangs = new ArrayList<Range>();
		PrintWriter printWriter = new PrintWriter(new FileWriter(workSpace + "overhangs.txt"));
		BufferedReader bufferedReader = new BufferedReader(new FileReader(coordsFile));
		String readLine = bufferedReader.readLine();
		ParseCoordsFileParser allContigsFileParser = new ParseCoordsFileParser();
		while(readLine != null)
		{
			String[] params = allContigsFileParser.parseCoordsFileLine(readLine);
			int startQuery = Integer.parseInt(params[2]);
			int endQuery = Integer.parseInt(params[3]);
			if (startQuery > endQuery)
			{
				int temp = startQuery; startQuery = endQuery; endQuery = temp;
			}
			int alignmentLength = Integer.parseInt(params[5]);
			int length = Integer.parseInt(params[8]);
			if (alignmentLength != length)
			{
				printWriter.println(readLine);
				overHangs.add(new Range(startQuery,endQuery,readLine));
			}
			readLine = bufferedReader.readLine();
		}

		printWriter.println("\n\n\n");
		for (Range contig : contigs)
		{
			for (Range rng : overHangs)
			{
				String[] params = allContigsFileParser.parseCoordsFileLine(rng.getMetadata());
				String name = params[14].trim();
				if (contig.getMetadata().equalsIgnoreCase(name))
				{
					printWriter.println(contig.getLowerLimit() + " " + 
							contig.getUpperLimit() + " " + contig.getMetadata());
					break;
				}
			}
		}
		bufferedReader.close();
		printWriter.flush();
		printWriter.close();

	}
	public void print(ArrayList<Range> contigs, ArrayList<Range> gaps,String scaffold) throws IOException
	{
		PrintWriter printWriter = new PrintWriter(new FileWriter(scaffold));
		for (int i = 0 ; i < contigs.size() ; i++)
		{
			Range contig = contigs.get(i);
			printWriter.println(contig.getLowerLimit() + " " + contig.getUpperLimit() + "  contig");
			if ( i < gaps.size())
			{
				Range gap = gaps.get(i);
				printWriter.println(gap.getLowerLimit() + " " + gap.getUpperLimit() + "  gap " );
			}
		}
		printWriter.flush();
		printWriter.close();
	}

	public ArrayList<Range> mergeOverLappingContigs(ArrayList<Range> contigsList, int seQLength)
	{
		ArrayList<Range> result = new ArrayList<Range>();

		for (Range contigRange : contigsList)
		{
			int start = contigRange.getLowerLimit();
			if (result.size() > 0)
			{
				Range lastRange = result.get(result.size()  - 1);
				//				int previousStart = lastRange.getUpperLimit();
				int previousEnd = lastRange.getUpperLimit();
				if (previousEnd >= start || (previousEnd + 1) == start )
				{
					int overLap = start - previousEnd - 1;
					int overLapcounter = result.size();
					lastRange = result.remove(result.size()  - 1);
					String name = lastRange.getMetadata();
					Range range = null;
					if (name.contains("_overLap"))
					{
						name = name.split("_overLap")[0];
						range = new Range(lastRange.getLowerLimit(), contigRange.getUpperLimit(), 
								name + "_" + contigRange.getMetadata() + " _overLap" + overLapcounter);
					}
					else
					{
						range = new Range(lastRange.getLowerLimit(), contigRange.getUpperLimit(), 
								lastRange.getMetadata() + "_" + contigRange.getMetadata() + " _overLap" + overLapcounter);
					}
					range = range.setActualLength(lastRange.getActualLength() + overLap + contigRange.getActualLength());
					result.add(range);
				}
				else
				{
					result.add(contigRange);
				}
			}
			else
			{
				result.add(contigRange);
			}
		}
		return result;
	}

	public int findTotalLengthOfRanges(ArrayList<Range> list)
	{
		int result = 0;
		for (Range range : list)
		{
			result = result + range.length();
		}
		return result;
	}

	public void makeVisualisation(ArrayList<Range> gaps,int seqLength, ArrayList<Range> excludedOnes,
			ArrayList<Range> contigs) throws ParserConfigurationException
			{
		//		String[] slots = new String[3];slots[0] = "contigs"; slots[1] = "excludedContigs"; slots[2] = "Gaps";
		//		String[] slots = new String[2];slots[0] = "454-Gamma70"; slots[1] = "Genes Annotated";
		String[] slots = new String[1];slots[0] = "All Genes";
		initialise(String.valueOf(seqLength),slots);
		makeFeatureSlots(slots.length);

		//		for (Range range : contigs)
		//		{
		//			int start = Integer.parseInt(String.valueOf(range.getLowerLimit()));
		//			if (start < 0 ) 
		//			{
		//				start = 4639675 + start;
		//				System.out.println("Negative start value \n " + range.getMetadata());
		//			}
		//			String mouseOver = "Start = " + String.valueOf(range.getLowerLimit())
		//			+ ", stop = " + String.valueOf(range.getUpperLimit());
		//			Element feature = prepareXMLFile.createFeature("directStrand0", colors[0], "clockwise-arrow", 
		//			range.getMetadata(), null,mouseOver,null,null,null);
		//			prepareXMLFile.createFeatureRange(feature, String.valueOf(start), 
		//					String.valueOf(range.getUpperLimit()), null);
		//		}

		for (Range range : gaps)
		{
			int start = Integer.parseInt(String.valueOf(range.getLowerLimit()));
			if (start < 0 ) 
			{
				start = 4639675 + start;
				System.out.println("Negative start value \n " + range.getMetadata());
			}
			String mouseOver = "Start = " + String.valueOf(range.getLowerLimit())
			+ ", stop = " + String.valueOf(range.getUpperLimit());
			Element feature = prepareXMLFile.createFeature("directStrand0", colors[0], "clockwise-arrow", 
					range.getMetadata(), null,mouseOver,null,null,null);
			prepareXMLFile.createFeatureRange(feature, String.valueOf(start), 
					String.valueOf(range.getUpperLimit()), null);
		}


		//		for (Range range : excludedOnes)
		//		{
		//			String qalignmentCoverage = range.getMetadata().split("\t")[10];
		//			String mouseOver = "Start = " + String.valueOf(range.getLowerLimit())
		//			+ ", stop = " + String.valueOf(range.getUpperLimit()) + " acov = " + qalignmentCoverage;
		//			String name = range.getMetadata().split("\t")[14];
		//			Element feature = prepareXMLFile.createFeature("directStrand1", colors[1], "clockwise-arrow", 
		//			name.trim(), null,mouseOver,null,null,null);
		//			prepareXMLFile.createFeatureRange(feature, String.valueOf(range.getLowerLimit()), 
		//					String.valueOf(range.getUpperLimit()), null);
		//		}


		//		int i = 0;
		//		for (Range range : gaps)
		//		{
		//			String mouseOver = "Start = " + String.valueOf(range.getLowerLimit())
		//			+ ", stop = " + String.valueOf(range.getUpperLimit());
		//			Element feature = prepareXMLFile.createFeature("directStrand1", colors[1], "clockwise-arrow", 
		//			"gap_"+i, null,mouseOver,null,null,null);
		//			i++;
		//			prepareXMLFile.createFeatureRange(feature, String.valueOf(range.getLowerLimit()), 
		//					String.valueOf(range.getUpperLimit()), null);
		//		}
		//		prepareXMLFile.writeToFile(workSpace + "vXml.xml");
		prepareXMLFile.writeToFile("C:/Users/bansalp/Desktop/DeNovo/DeNovo/" + "vXml.xml");
			}

	private void initialise(String seqLength, String[] args) throws ParserConfigurationException 
	{
		prepareXMLFile = new PrepareXMLFile().createCGView(seqLength)
		.createLegend("sideLegend", "upper-right", "SanSerif, plain, 10", "0.8");

		for (int i = 0; i < args.length; i++)
		{
			String legendLabel = args[i];
			prepareXMLFile = prepareXMLFile.createLegendItem("sideLegend", legendLabel, "SanSerif, plain, 12", true, colors[i]);
		}
		prepareXMLFile = prepareXMLFile.createLegend("lowerleftlegend", "lower-left", "SanSerif, plain, 9", "0.8")
		.createLegendItem("lowerleftlegend", "This map was generated using CGView", null, false, null)
		.createLegend("lowerrightlegend", "lower-right", "SanSerif, plain, 9", "0.8")
		.createLegendItem("lowerrightlegend", "Work done at D-BSSE ETH Zurich", null, false, null);
	}

	private void makeFeatureSlots(int slots) 
	{
		for(int i = 0; i < slots; i++)
		{
			prepareXMLFile = prepareXMLFile.createFeatureSlots("directStrand" + i, "direct",false);
		}
	}


	/**
	 * This method fetches the range of contigs whose name is specified by the list
	 * @param list
	 * @param coordsFile
	 * @return
	 * @throws IOException
	 */
	public ArrayList<ArrayList<Range>> findExcludedContigRanges(ArrayList<String> list,
			String coordsFile) throws IOException 
			{
		ArrayList<ArrayList<Range>> result = new ArrayList<ArrayList<Range>>();
		TreeSet<String> temp_list = new TreeSet<String>(list);

		ArrayList<Range> excluded = new ArrayList<Range>();
		ArrayList<Range> contigsNotAligned = new ArrayList<Range>();

		BufferedReader bufferedReader = new BufferedReader(new FileReader(coordsFile));
		String readLine = bufferedReader.readLine();
		ParseCoordsFileParser allContigsFileParser = new ParseCoordsFileParser();
		while(readLine != null)
		{
			String[] params = allContigsFileParser.parseCoordsFileLine(readLine);
			if (list.contains(params[14].trim()))
			{
				int start = Integer.parseInt(params[0].trim());
				int end  = Integer.parseInt(params[1].trim());
				if (start > end)
				{
					int temp = start; start = end ; end = temp;
				}
				if (start < 0)
				{
					start = 4639675 + start;
					System.out.println("negative for \n params[14]");
				}
				Range range = new Range(start, end, readLine.trim());
				excluded.add(range);
				temp_list.remove(params[14].trim());
			}
			readLine = bufferedReader.readLine();
		}
		bufferedReader.close();
		for (String contig : temp_list)
		{
			Range range = new Range(0, 0, contig);
			contigsNotAligned.add(range);
		}
		result.add(excluded);
		result.add(contigsNotAligned);
		return result;
			}

	public ArrayList<ArrayList<Range>> FilterGenesFoundAndNotFoundInGaps(HashMap<Range, ArrayList<Range>> hashMap,
			String MissingGenesFile, String genesFoundFile, String resultGff3File) throws IOException
			{
		ArrayList<ArrayList<Range>> result = new ArrayList<ArrayList<Range>>();
		ArrayList<Range> missingGenesList = new ArrayList<Range>();
		ArrayList<Range> foundGenesList = new ArrayList<Range>();
		PrintWriter notFoundGenes = new PrintWriter(new FileWriter(MissingGenesFile));
		PrintWriter foundGenes = new PrintWriter(new FileWriter(genesFoundFile));

		// all genes that were found in the sequence
		ArrayList<Range> genesFound = new PrepareGFF3().setOutputFile(resultGff3File)
		.findRanges();
		Range firstElementRemoved = genesFound.remove(genesFound.size() - 1);
		System.out.println(firstElementRemoved.getMetadata());
		//		FileUtilities.WriteToFile(genesFound, workSpace + "test.txt");
		Collections.sort(genesFound,new RangeComparator());
		// this is the contig info which is not required

		// all genes found in the gaps
		ArrayList<Range> gapsWithGenes = new ArrayList<Range>(hashMap.keySet());
		Collections.sort(gapsWithGenes,new RangeComparator());

		for (Range gap : gapsWithGenes)
		{
			// list of genes possible in this gap
			ArrayList<Range> possibleGenes = hashMap.get(gap);
			for (Range possibleGene : possibleGenes)
			{
				Range found = null;
				// check if we have already found this gene somewhere else or not
				for (Range geneFound : genesFound)
				{
					if (geneFound.getMetadata().equalsIgnoreCase(possibleGene.getMetadata()))
					{
						found = geneFound; break;
					}
				}
				// if we have found this gene somewhere else then write this
				if (found != null)
				{
					String toPrint = gap.getLowerLimit() + "\t" +
					gap.getUpperLimit() + "\t" +
					gap.getMetadata() + "\t" +
					possibleGene.getLowerLimit() + "\t" + 
					possibleGene.getUpperLimit() + "\t" + 
					possibleGene.getMetadata() + "\t" +
					found.getLowerLimit() + "\t" +
					found.getUpperLimit() + "\t" +
					found.getMetadata();
					foundGenes.println(toPrint);
					foundGenesList.add(found);
				}
				// if we haven't accounted for this gene then write this
				else
				{
					//					String toPrint = gap.getLowerLimit() + "\t" +
					//					   gap.getUpperLimit() + "\t" +
					//					   gap.getMetadata() + "\t" +
					//					   possibleGene.getLowerLimit() + "\t" + 
					//					   possibleGene.getUpperLimit() + "\t" + 
					//					   possibleGene.getMetadata();
					String toPrint = possibleGene.getMetadata();
					notFoundGenes.println(toPrint);
					missingGenesList.add(possibleGene);
				}
			}
		}
		foundGenes.flush();
		foundGenes.close();
		notFoundGenes.flush();
		notFoundGenes.close();
		result.add(foundGenesList);
		result.add(missingGenesList);
		// total genes
		result.add(genesFound);
		return result;
			}

	/**
	 * This finds a map that maps gaps to the list of genes that could
	 * be in them based on the reference sequence. This keySet from this map
	 * will be a subset of the total gaps because some gaps may not have any genes in them.
	 * @param gaps
	 * @param allGenes
	 * @return
	 * @throws IOException 
	 */
	public HashMap<Range, ArrayList<Range>> findGenesInGaps(ArrayList<Range> gaps, ArrayList<Range> allGenes,
			String noGenesGapFile) throws IOException
			{
		ArrayList<Range> noGenesGaps = new ArrayList<Range>();
		HashMap<Range, ArrayList<Range>> hashMap = new HashMap<Range, ArrayList<Range>>();
		for (Range range : gaps)
		{
			ArrayList<Range> overLap = new ArrayList<Range>();
			for (Range gene : allGenes)
			{
				if (gene.getLowerLimit() > range.getUpperLimit())
				{
					break;
				}
				else
				{
					if (!gene.exclusive(range))
					{
						overLap.add(gene);
					}
				}
			}
			if (overLap.size() > 0) hashMap.put(range, overLap);
			else noGenesGaps.add(range);
		}
		Collections.sort(noGenesGaps,new RangeComparator());
		FileUtilities.WriteToFile(noGenesGaps, noGenesGapFile);
		return hashMap;
			}

	public ArrayList<Range> pickContigsFromBlastResults(String hitsFile,String outputFile) throws IOException
	{
		ArrayList<Range> result = new ArrayList<Range>();
		BufferedReader bufferedReader = new BufferedReader(new FileReader(hitsFile));
		String readLine = bufferedReader.readLine();
		while(readLine != null)
		{
			if (!readLine.startsWith("#"))
			{
				String[] params = readLine.split("\t");
				if (params[2].trim().equalsIgnoreCase("100.00") &&
						(Integer.parseInt(params[4].trim()) == 1 || Integer.parseInt(params[4].trim()) == 0) && 
						(Integer.parseInt(params[4].trim()) == 1 || Integer.parseInt(params[4].trim()) == 0))
				{
					int start = Integer.parseInt(params[8].trim());
					int end = Integer.parseInt(params[9].trim());
					if (start > end)
					{
						int temp = start; start = end ; end = temp;
					}
					String name = params[0];
					Range range = new Range(start, end, name);
					result.add(range);
				}	
			}
			readLine = bufferedReader.readLine();
		}
		Collections.sort(result,new RangeComparator());
		FileUtilities.WriteToFile(result, outputFile);
		return result;
	}

	/**
	 * This method filters the tiling File and fetches the contigs and the possible gaps.
	 * It doesn't take into account that the contigs could be overlapping.
	 * @param seqLength
	 * @param tilingFile
	 * @param gapsFile
	 * @param contigsFile
	 * @return A list containing two lists: first one is a list of contigs and second one is the 
	 * 			list of gaps.
	 * @throws IOException
	 */
	public ArrayList<ArrayList<Range>> filterTilingFile(int seqLength, String tilingFile, 
			String gapsFile, String contigsFile) throws IOException
			{
		ArrayList<ArrayList<Range>> result = new ArrayList<ArrayList<Range>>();
		ArrayList<Range> gapList = new ArrayList<Range>();
		ArrayList<Range> contigs = new ArrayList<Range>();

		// start reading the tiling file
		BufferedReader bufferedReader = new BufferedReader(new FileReader(tilingFile));
		String readLine = bufferedReader.readLine();
		int current = 1;
		int overlapping = 1;
		while(readLine != null)
		{
			if (!readLine.startsWith(">"))
			{
				String[] params = readLine.split("\t");
				int start = Integer.parseInt(params[0]);
				int end = Integer.parseInt(params[1]);
				double alignmentCov =  Double.parseDouble(params[5]);
				double actualLength = (alignmentCov * Integer.parseInt(params[3].trim()))/100;
				Range contig = new Range(start, end, params[7].trim(),Integer.parseInt(params[3].trim())).setActualLength((double)Math.round(actualLength));
				contigs.add(contig);
				if (current < start)
				{
					Range range = new Range(current, start - 1, params[7].trim());
					gapList.add(range);
					current = end + 1;
				}
				else if (current >= start && current < end)
				{
					overlapping++;
					current = end + 1;
				}
				else if (current > end)
				{

				}
			}
			readLine = bufferedReader.readLine();
		}
		if (current < seqLength) 
		{
			int ultimateStarter = contigs.get(0).getLowerLimit();
			int diff = 0;
			if (ultimateStarter < 0)
			{
				diff = ultimateStarter  - 1;
			}
			Range range = new Range(current, seqLength + diff, "trailing");
			gapList.add(range);
		}
		Collections.sort(gapList,new RangeComparator());
		FileUtilities.WriteToFile(gapList, gapsFile);
		Collections.sort(contigs,new RangeComparator());
		FileUtilities.WriteToFile(contigs, contigsFile);
		result.add(contigs); result.add(gapList);
		return result;
			}
}

class RangeComparator implements Comparator<Range>
{
	@Override
	public int compare(Range o1, Range o2) {
		int diff =  o1.getLowerLimit() - o2.getLowerLimit();
		if (diff == 0)
		{
			diff = o1.getUpperLimit() - o2.getUpperLimit();
		}
		return diff;
	}
}	
